package com.smallA.association.config;

import com.smallA.association.constant.UserConstant;
import com.smallA.association.filter.JwtLoginFilter;
import com.smallA.association.filter.JwtVerityFilter;
import com.smallA.association.service.AssociationService;
import com.smallA.association.service.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;

/**
 * @author 君未洋
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //继承了这个类之后就相当于这个类拥有所有的SpringSecurity所有的配置

    @Resource
    private UserService userService;

    @Resource
    private RsaKeyProperties prop;

    @Resource
    private AssociationService associationService;

    /**
     * 这个就是配置的一个将加密类加入到Spring的容器中的方式
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/Test/*")
                .and().ignoring().antMatchers("/User/getCode")
                .and().ignoring().antMatchers("/User/registeredAssociation")
                .and().ignoring().antMatchers("/css/*")
                .and().ignoring().antMatchers("/js/*")
                .and().ignoring().antMatchers("/index.html")
                .and().ignoring().antMatchers("/favicon.ico");
    }

    /**
     * 这个就是认证用户的来源了
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }

    /**
     * 配置SpringSecurity基本配置
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /*这里就是配置基本的登录页面,角色,登录相关的提交等等等*/
        http.authorizeRequests()
                //.antMatchers("/test").permitAll()
                .antMatchers("/**").hasAnyRole(UserConstant.ROLE_BASE_ACCESS)
                .anyRequest()
                .authenticated();
        //这里就代表/**下的资源只有在认证通过之后才能访问到
        //释放掉处理配置的这些基本页面
        /*配置下注销按钮*/
        http.logout().logoutUrl("/logout")
                .invalidateHttpSession(true)
                //这个就是配置的是否清空session
                .permitAll();
        //这里还要再配置对应的拦截要重新配置

        /*配置登录对应的拦截器*/
        http.addFilter(new JwtLoginFilter(super.authenticationManager(), prop, associationService))
                .addFilter(new JwtVerityFilter(super.authenticationManager(), prop))
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        //这里就是禁用掉session了,表示我们不再使用session

        http.cors().configurationSource(CorsConfigurationSource());
        //
        http.csrf().disable();
        //关闭csrf,有一个要注意的就是csrf被认为是后面不能再操作了,所以你会发现这个后面是没有and的
    }

    /*配置跨域访问资源*/
    private CorsConfigurationSource CorsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        //同源配置，*表示任何请求都视为同源，若需指定ip和端口可以改为如“localhost：8080”，多个以“，”分隔；
        corsConfiguration.addAllowedHeader("*");
        //header，允许哪些header，本案中使用的是token，此处可将*替换为token；
        corsConfiguration.addAllowedMethod("*");
        //允许的请求方法，PSOT、GET等
        source.registerCorsConfiguration("/**", corsConfiguration);
        //配置允许跨域访问的url
        return source;
    }
}
